#ifndef DEFMOD_MODULE_REGISTRY_HPP
#define DEFMOD_MODULE_REGISTRY_HPP

#include "Module/DefModConfig.hpp"
#include <map>

namespace AbsUI {  class UICommandRegistry; class MainWindow; class ConnCfgWidgetFactory; }
namespace Storage { class ConnectionConfigFactory; class ConnectionConfigCollection; }

namespace Module
{

class AbstractModule;

/// \ingroup Module
/// \brief It manages the registered modules.
/// \details
///		It also refers to the various registration centers needed by the modules to initialize, also providing access to 
///		them.
class MODULE_API ModuleRegistry
{
private:
	/// \details It registers the default module.
	ModuleRegistry();

public:
	virtual ~ModuleRegistry();

	static ModuleRegistry& instance();

	/// \pre The specified main window is not NULL.
	/// \pre The specified UI command registry is not NULL.
	/// \pre This method is called for the first time.
	static void configure( 
		AbsUI::MainWindow* pMainWindow, 
		AbsUI::UICommandRegistry* pUICommandReg, 
		AbsUI::ConnCfgWidgetFactory* pConnCfgWidgetFactory,
		Storage::ConnectionConfigFactory* pConnCfgFactory,
		Storage::ConnectionConfigCollection* pConnCfgColl);

	/// \brief It registers the specified module.
	/// \pre the specified module is not NULL.
	/// \pre the module is not already registered.
	/// \details
	///		It calls the initialization method of the module, to provide that module the possibility to the application 
	///		with the needed stuff.
	void registerModule( AbstractModule* pModule);

	/// \brief It gets the module identified by the specified identifier.
	/// \pre the specified identifier is associated with a registered module.
	/// \{
	const AbstractModule& module( const std::string& moduleID) const;
	AbstractModule& module( const std::string& moduleID);
	/// \}

	/// \brief It checks whether the specified module or module identifier is registered.
	/// \{
	bool isModuleRegistered( const std::string& moduleID) const;
	bool isModuleRegistered( const AbstractModule& module) const;
	/// \}

	/// \brief It provides access to the UI command registry.
	/// \{
	const AbsUI::UICommandRegistry& uiCmdRegistry() const { return *pCmdRegistry_; }
	AbsUI::UICommandRegistry& uiCmdRegistry() { return *pCmdRegistry_; }
	/// \}

	/// \brief It provides access to the main window of the application.
	/// \{
	const AbsUI::MainWindow& mainWindow() const { return *pMainWindow_; }
	AbsUI::MainWindow& mainWindow() { return *pMainWindow_; }
	/// \}

	/// \brief It gets the connection configuration factory.
	/// \{
	const Storage::ConnectionConfigFactory& connConfigFactory() const { return *pConnConfigFactory_; }
	Storage::ConnectionConfigFactory& connConfigFactory() { return *pConnConfigFactory_; }
	/// \}

	/// \brief It gets the connection configuration widget factory.
	/// \{
	const AbsUI::ConnCfgWidgetFactory& connCfgWidgetFactory() const { return *pConnCfgWidgetFactory_; }
	AbsUI::ConnCfgWidgetFactory& connCfgWidgetFactory() { return *pConnCfgWidgetFactory_; }
	/// \}

	/// \brief It gets the connection configurations available.
	/// \{
	const Storage::ConnectionConfigCollection& connCfgCollection() const { return *pConnCfgCollection_; }
	Storage::ConnectionConfigCollection& connCfgCollection() { return *pConnCfgCollection_; }
	/// \}

public:
	static const std::string CONNECTIONS_FILE_PATH;
private:
	typedef std::map< std::string, AbstractModule*> ModuleMap;
	ModuleMap registeredModules_;
	AbsUI::UICommandRegistry* pCmdRegistry_;
	AbsUI::MainWindow* pMainWindow_;
	Storage::ConnectionConfigFactory* pConnConfigFactory_;
	AbsUI::ConnCfgWidgetFactory* pConnCfgWidgetFactory_;
	Storage::ConnectionConfigCollection* pConnCfgCollection_;
};

} // namespace Module

#endif // DEFMOD_MODULE_REGISTRY_HPP
